package ObjectVC;

import java.util.ArrayList;
import java.util.Date;
import java.util.Hashtable;
import java.util.Set;

import javax.swing.JOptionPane;

class DB {	
	private static Hashtable<Date, ArrayList<Version>> versionsByTime = 
		new Hashtable<Date, ArrayList<Version>>();
	private static Hashtable<Object, ObjectVersions> versionsByObj = 
		new Hashtable<Object, ObjectVersions>();
	private static ArrayList<Object> lockedObjects = new ArrayList<Object>();
	//private Hashtable<Class<?>, ObjectVersions> versionsOfTypes = 
		//new Hashtable<Class<?>, ObjectVersions>();
	
	static Set<Object> getAllObjs(){
		return versionsByObj.keySet();
	}
	
	static Version getVersion(Object obj, Date date) {
		ArrayList<Version> list = allVersionsWithTimestamp(date);
		if (null != list){
			int idx = list.indexOf(obj);
			if (-1 != idx)
				return list.get(idx);
			JOptionPane.showMessageDialog(null, "There's no version from this date for this object");				
		}
		return null;
	}
	
	static ArrayList<Version> allVersionsWithTimestamp(Date date){
		if (null != date){
			ArrayList<Version> list = versionsByTime.get(date);
			if (null != list)				
				return list;
			JOptionPane.showMessageDialog(null, "There are no versions from this date in VC database");
		}
		else
			JOptionPane.showMessageDialog(null, "Parameter is null");
		return null;
	}
	
	/*static Version getVersion(Object obj, Version ver) {
		ArrayList<Version> list = getVersionList(obj);
		if (null != list){
			int idx = list.indexOf(ver);
			if (-1 > idx)
				return list.get(idx);
				
			JOptionPane.showMessageDialog(null, "This version doesn't exist for this object");
		}
		return null;
	}*/
	
	static Version getVersion(Object obj, int idx) {
		Version ov = null;
		
		if (idx < 0)
			JOptionPane.showMessageDialog(null, "Invalid parameter");
		ArrayList<Version> list = getVersionList(obj);
		if (null != list){
			for (Version objectVersion : list) {
				if (objectVersion.getIndex() == idx)
					ov = objectVersion;
			}
			
			if (ov == null)
				JOptionPane.showMessageDialog(null, "Version number " + idx + "doesn't exist for this object");
		}
		return ov;
	}
	
	static Version getLatestVersion(Object obj) {
		ArrayList<Version> list = getVersionList(obj);
		if (null != list)
			return list.get(list.size()-1);	//the list cannot be empty because we add a version whe we add the object to VC DB
		return null;
	}
	
	static ArrayList<Version> getVersionList(Object obj){
		ObjectVersions ov = versionsByObj.get(obj);
		if (null != ov)			
			return ov.versionList;
		
		JOptionPane.showMessageDialog(null, "This object doesn't appear in the Object VC database");
		return null;
	}
	
	static void addVersion(Object obj, String comment){
		Date timestamp = new Date();
		Version objVer = new Version(obj, timestamp, comment);
		ArrayList<Version> newList = new ArrayList<Version>();
		
		ObjectVersions ovObj = versionsByObj.get(obj);
		if (null != ovObj)
			ovObj.versionList.add(objVer);
		else{
			JOptionPane.showMessageDialog(null, "This object doesn't appear in the Object VC database");
			return;
		}
		
		ArrayList<Version> list = versionsByTime.get(timestamp);
		if (null == list)
			versionsByTime.put(timestamp, newList);
		else
			list.add(objVer);
	}
	
	static boolean addToDB(Object obj, Date timestamp, String comment, VCMode mode){
		Version objVer = new Version(obj, timestamp, comment);
		ArrayList<Version> newList = new ArrayList<Version>();
		newList.add(objVer);
		ObjectVersions newOV = new ObjectVersions(objVer, comment, mode); 
		
		ObjectVersions ov = versionsByObj.get(obj);
		ArrayList<Version> list = versionsByTime.get(timestamp);
		if (null == ov && null == list){
			versionsByObj.put(obj, newOV);
			versionsByTime.put(timestamp, newList);
			return true;
		}
		else	//obj already is in VC DB
			JOptionPane.showMessageDialog(null, "This object already appears in the VC database");
		return false;
	}
	
	/*static void deleteVersion(Object obj, Version objVer){
		if (false == getVersionList(obj).remove(objVer))
		{
			JOptionPane.showMessageDialog(null, "This version doesn't exist for this object");
			return;
		}
		
		ArrayList<Version> list = versionsByTime.get(objVer.getTimestamp());
		if (null != list)
			list.remove(objVer);
			
	}*/
	
	static void deleteVersion(Object obj, int idx){
		Version objVer;
		try{
			objVer = getVersionList(obj).remove(idx);
		}
		catch(IndexOutOfBoundsException e){
			JOptionPane.showMessageDialog(null, "Version number " + idx + "doesn't exist for this object");
			return;
		}
		
		ArrayList<Version> list = versionsByTime.get(objVer.getTimestamp());
		if (null != list)
			list.remove(objVer);
	}
	
	static void deleteVersion(Object obj, Date timestamp){
		Version ver = null;
		ObjectVersions ov = versionsByObj.get(obj);
		if (null == ov){
			JOptionPane.showMessageDialog(null, "There's no version for this object");
			return;
		}
		
		for(Version v : ov.versionList) {
			if(v.getTimestamp().equals(timestamp)){
				ver = v;
				break;
			}
		}
		if(null != ver)
			ov.versionList.remove(ver);
		
		ArrayList<Version> list = versionsByTime.get(timestamp);
		if (null != list)
			list.remove(ver);
		else
			JOptionPane.showMessageDialog(null, "There's no version from this date for this object");
	}
	
	static void deleteObject(Object obj){
		ArrayList<Version> versionList = getVersionList(obj);
		for (int i = 0; i < versionList.size(); i++) {
			Date timestamp = versionList.get(i).getTimestamp();
			ArrayList<Version> list = versionsByTime.get(timestamp);
			list.remove(obj);
			if(list.isEmpty())
				versionsByTime.remove(timestamp);			
		}
		
		versionsByObj.remove(obj);
	}
	
	static void deleteObjVersions(Object obj){
		ArrayList<Version> versionList = getVersionList(obj);
		for (int i = 0; i < versionList.size(); i++) {
			Date timestamp = versionList.get(i).getTimestamp();
			ArrayList<Version> list = versionsByTime.get(timestamp);
			list.remove(obj);
		}
		
		versionsByObj.get(obj).versionList = new ArrayList<Version>();
	}
	
	static VCMode contains(Object obj){
		ObjectVersions ov = versionsByObj.get(obj);
		if (null != ov)			
			return ov.mode;
		
		JOptionPane.showMessageDialog(null, "This object doesn't appear in the Object VC database");
		return null;
	}
	
	static void lockObject(Object obj){
		if (isLocked(obj))
			JOptionPane.showMessageDialog(null, "This object is already locked");
		else
			lockedObjects.add(obj);
	}
	
	static void unlockObject(Object obj){
		if (!isLocked(obj))
			JOptionPane.showMessageDialog(null, "This object wasn't locked");
		else
			lockedObjects.remove(obj);
	}
	
	static boolean isLocked(Object obj){
		return lockedObjects.contains(obj);
	}
}
